home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d2
/
v8n12.arc
/
TAQUIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-05
|
12KB
|
292 lines
/*---------------------------------------------------------
TAQUIN.C -- Jeu de Taquin for OS/2 Presentation Manager
(c) 1989, Ziff Communications Co.
PC Magazine * Charles Petzold, January 1989
---------------------------------------------------------*/
#define INCL_WIN // include 'Win' functions in OS/2 headers
#define INCL_GPI // include 'Gpi' functions in OS/2 headers
#include <os2.h>
#include <stdlib.h>
#include "taquin.h"
#define NUMROWS 4 // greater than or equal to 2
#define NUMCOLS 4 // greater than or equal to 3
#define SCRAMBLEREP 100 // make larger if using more than 16 square
#define SQUARESIZE 67 // in 1/100th inch
MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
MRESULT EXPENTRY AboutDlgProc (HWND, USHORT, MPARAM, MPARAM) ;
int main (void)
{
static CHAR szClientClass[] = "Taquin" ;
static ULONG flFrameFlags = FCF_SYSMENU | FCF_TITLEBAR |
FCF_BORDER | FCF_MINBUTTON |
FCF_MENU | FCF_ICON |
FCF_TASKLIST ;
HAB hab ;
HMQ hmq ;
HWND hwndFrame, hwndClient ;
QMSG qmsg ;
// Initialize and create standard window
hab = WinInitialize (0) ;
hmq = WinCreateMsgQueue (hab, 0) ;
WinRegisterClass (hab, szClientClass, ClientWndProc, 0L, 0) ;
hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
&flFrameFlags, szClientClass, NULL,
0L, NULL, ID_RESOURCE, &hwndClient) ;
// Get messages from queue and dispatch them
while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
WinDispatchMsg (hab, &qmsg) ;
// Clean up and terminate
WinDestroyWindow (hwndFrame) ;
WinDestroyMsgQueue (hmq) ;
WinTerminate (hab) ;
return 0 ;
}
MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
static SHORT asPuzzle[NUMROWS][NUMCOLS],
sBlankRow, sBlankCol, cxSquare, cySquare ;
CHAR szNum[5] ;
HPS hps ;
HWND hwndFrame ;
POINTL ptl ;
RECTL rcl, rclInvalid, rclIntersect ;
SHORT sRow, sCol, sMouseRow, sMouseCol, i ;
SIZEL sizl ;
switch (msg)
{
case WM_CREATE:
// Calculate square size in pixels
hps = WinGetPS (hwnd) ;
sizl.cx = sizl.cy = 0 ;
GpiSetPS (hps, &sizl, PU_LOENGLISH) ;
ptl.x = SQUARESIZE ;
ptl.y = SQUARESIZE ;
GpiConvert (hps, CVTC_PAGE, CVTC_DEVICE, 1L, &ptl) ;
WinReleasePS (hps) ;
cxSquare = (SHORT) ptl.x ;
cySquare = (SHORT) ptl.y ;
// Calculate client window size and position
rcl.xLeft = (WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) -
NUMCOLS * cxSquare) / 2 ;
rcl.yBottom = (WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) -
NUMROWS * cySquare) / 2 ;
rcl.xRight = rcl.xLeft + NUMCOLS * cxSquare ;
rcl.yTop = rcl.yBottom + NUMROWS * cySquare ;
// Set frame window position and size
hwndFrame = WinQueryWindow (hwnd, QW_PARENT, FALSE) ;
WinCalcFrameRect (hwndFrame, &rcl, FALSE) ;
WinSetWindowPos (hwndFrame, NULL,
(SHORT) rcl.xLeft, (SHORT) rcl.yBottom,
(SHORT) (rcl.xRight - rcl.xLeft),
(SHORT) (rcl.yTop - rcl.yBottom),
SWP_MOVE | SWP_SIZE | SWP_ACTIVATE) ;
// Initialize the asPuzzle array
WinSendMsg (hwnd, WM_COMMAND, MPFROMSHORT (IDM_NORMAL), NULL) ;
return 0 ;
case WM_PAINT:
hps = WinBeginPaint (hwnd, NULL, &rclInvalid) ;
// Draw the squares
for (sRow = NUMROWS - 1 ; sRow >= 0 ; sRow--)
for (sCol = 0 ; sCol < NUMCOLS ; sCol++)
{
rcl.xLeft = cxSquare * sCol ;
rcl.yBottom = cySquare * sRow ;
rcl.xRight = rcl.xLeft + cxSquare ;
rcl.yTop = rcl.yBottom + cySquare ;
if (!WinIntersectRect (NULL, &rclIntersect,
&rcl, &rclInvalid))
continue ;
if (sRow == sBlankRow && sCol == sBlankCol)
WinFillRect (hps, &rcl, CLR_BLACK) ;
else
{
WinDrawBorder (hps, &rcl, 5, 5,
CLR_PALEGRAY, CLR_DARKGRAY,
DB_STANDARD | DB_INTERIOR) ;
WinDrawBorder (hps, &rcl, 2, 2,
CLR_BLACK, 0L, DB_STANDARD) ;
WinDrawText (hps, -1,
itoa (asPuzzle[sRow][sCol], szNum, 10),
&rcl, CLR_WHITE, CLR_DARKGRAY,
DT_CENTER | DT_VCENTER) ;
}
}
WinEndPaint (hps) ;
return 0 ;
case WM_BUTTON1DOWN:
sMouseCol = MOUSEMSG(&msg)->x / cxSquare ;
sMouseRow = MOUSEMSG(&msg)->y / cySquare ;
// Check if mouse was in valid area
if ( sMouseRow < 0 || sMouseCol < 0 ||
sMouseRow >= NUMROWS || sMouseCol >= NUMCOLS ||
(sMouseRow != sBlankRow && sMouseCol != sBlankCol) ||
(sMouseRow == sBlankRow && sMouseCol == sBlankCol))
break ;
// Move a row right or left
if (sMouseRow == sBlankRow)
{
if (sMouseCol < sBlankCol)
for (sCol = sBlankCol ; sCol > sMouseCol ; sCol--)
asPuzzle[sBlankRow][sCol] =
asPuzzle[sBlankRow][sCol - 1] ;
else
for (sCol = sBlankCol ; sCol < sMouseCol ; sCol++)
asPuzzle[sBlankRow][sCol] =
asPuzzle[sBlankRow][sCol + 1] ;
}
// Move a column up or down
else
{
if (sMouseRow < sBlankRow)
for (sRow = sBlankRow ; sRow > sMouseRow ; sRow--)
asPuzzle[sRow][sBlankCol] =
asPuzzle[sRow - 1][sBlankCol] ;
else
for (sRow = sBlankRow ; sRow < sMouseRow ; sRow++)
asPuzzle[sRow][sBlankCol] =
asPuzzle[sRow + 1][sBlankCol] ;
}
// Calculate invalid rectangle
rcl.xLeft = cxSquare * min (sMouseCol, sBlankCol) ;
rcl.yBottom = cySquare * min (sMouseRow, sBlankRow) ;
rcl.xRight = cxSquare * (max (sMouseCol, sBlankCol) + 1) ;
rcl.yTop = cySquare * (max (sMouseRow, sBlankRow) + 1) ;
// Set new array and blank values
sBlankRow = sMouseRow ;
sBlankCol = sMouseCol ;
asPuzzle[sBlankRow][sBlankCol] = 0 ;
// Invalidate rectangle
WinInvalidateRect (hwnd, &rcl, FALSE) ;
break ;
case WM_CHAR:
if (!(CHARMSG(&msg)->fs & KC_VIRTUALKEY) ||
CHARMSG(&msg)->fs & KC_KEYUP)
return 0 ;
// Mimic a WM_BUTTON1DOWN message
sMouseCol = sBlankCol ;
sMouseRow = sBlankRow ;
switch (CHARMSG(&msg)->vkey)
{
case VK_LEFT: sMouseCol++ ; break ;
case VK_RIGHT: sMouseCol-- ; break ;
case VK_UP: sMouseRow-- ; break ;
case VK_DOWN: sMouseRow++ ; break ;
default: return 0 ;
}
WinSendMsg (hwnd, WM_BUTTON1DOWN,
MPFROM2SHORT (sMouseCol * cxSquare,
sMouseRow * cySquare), NULL) ;
return 0 ;
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
// Initialize asPuzzle array
case IDM_NORMAL:
case IDM_INVERT:
for (sRow = 0 ; sRow < NUMROWS ; sRow++)
for (sCol = 0 ; sCol < NUMCOLS ; sCol++)
asPuzzle[sRow][sCol] = sCol + 1 +
NUMCOLS * (NUMROWS - sRow - 1) ;
if (COMMANDMSG(&msg)->cmd == IDM_INVERT)
{
asPuzzle[0][NUMCOLS-2] = NUMCOLS * NUMROWS - 2 ;
asPuzzle[0][NUMCOLS-3] = NUMCOLS * NUMROWS - 1 ;
}
asPuzzle[sBlankRow = 0][sBlankCol = NUMCOLS - 1] = 0 ;
WinInvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;
// Randomly scramble the squares
case IDM_SCRAMBLE:
WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (
HWND_DESKTOP, SPTR_WAIT, FALSE)) ;
srand ((int) WinGetCurrentTime (NULL)) ;
for (i = 0 ; i < SCRAMBLEREP ; i++)
{
WinSendMsg (hwnd, WM_BUTTON1DOWN,
MPFROM2SHORT (rand() % NUMCOLS * cxSquare,
sBlankRow * cySquare), NULL) ;
WinUpdateWindow (hwnd) ;
WinSendMsg (hwnd, WM_BUTTON1DOWN,
MPFROM2SHORT (sBlankCol * cxSquare,
rand() % NUMROWS * cySquare), NULL) ;
WinUpdateWindow (hwnd) ;
}
WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (
HWND_DESKTOP, SPTR_ARROW, FALSE));
return 0 ;
// Display dialog box
case IDM_ABOUT:
WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
NULL, IDD_ABOUT, NULL) ;
return 0 ;
}
break ;
}
return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
}
MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
switch (msg)
{
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
case DID_OK:
case DID_CANCEL:
WinDismissDlg (hwnd, TRUE) ;
return 0 ;
}
break ;
}
return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
}